#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <time.h>
#include <WS2812FX.h>

// WiFi credentials
const char *ssid = "XingHuan";      // Replace with your WiFi name
const char *password = "xinghuan";  // Replace with your WiFi password

// MQTT Broker settings
const int mqtt_port = 8883;                                      // MQTT port (TLS)
const char *mqtt_broker = "ma0a8495.ala.cn-hangzhou.emqxsl.cn";  // EMQX broker endpoint
const char *mqtt_topic = "BOOK/WS2812B_kz";                      // MQTT subscribe topic
const char *topic = "BOOK/WS2812B_zt";                           // MQTT publish topic
const char *mqtt_username = "XingHuan_4";                        // MQTT username for authentication
const char *mqtt_password = "XingHuan";                          // MQTT password for authentication

// NTP Server settings
//const char *ntp_server = "pool.ntp.org";     // Default NTP server
const char *ntp_server = "cn.pool.ntp.org";  // Recommended NTP server for users in China
const long gmt_offset_sec = 0;               // GMT offset in seconds (adjust for your time zone)
const int daylight_offset_sec = 0;           // Daylight saving time offset in seconds


// WiFi and MQTT client initialization
BearSSL::WiFiClientSecure espClient;
PubSubClient mqtt_client(espClient);

// SSL certificate for MQTT broker
// Load DigiCert Global Root G2, which is used by EMQX Public Broker: broker.emqx.io
static const char ca_cert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
)EOF";

#define LED_PIN D8     //ESP8266-Node MCU开发板 D8引脚
#define LED_COUNT 240  //灯珠数量

uint8_t Mode = 0;      //初始模式  温馨提示：固定颜色为模式0
uint8_t Speed = 100;   //初始速度  由于存储设置限制，实际时间为10倍数 毫秒
uint8_t colorW = 255;  //初始亮度
uint8_t colorR = 255;  //初始颜色RGB
uint8_t colorG = 255;
uint8_t colorB = 255;

WS2812FX ws2812fx = WS2812FX(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
// Function declarations
void connectToWiFi();

void connectToMQTT();

void syncTime();

void mqttCallback(char *topic, byte *payload, unsigned int length);


void setup() {
  Serial.begin(115200);
  connectToWiFi();
  syncTime();  // X.509 validation requires synchronization time
  mqtt_client.setServer(mqtt_broker, mqtt_port);
  mqtt_client.setCallback(mqttCallback);
  connectToMQTT();

  ws2812fx.init();
  colorW = 127;
  ws2812fx.setBrightness(colorW);
  ws2812fx.setSpeed(Speed * 100);
  ws2812fx.setColor(colorR, colorG, colorB);
  ws2812fx.setMode(Mode);
  ws2812fx.start();
  Serial.println(F("模式："));
  Serial.println(ws2812fx.getModeName(Mode));
}

void connectToWiFi() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");
}

void syncTime() {
  configTime(gmt_offset_sec, daylight_offset_sec, ntp_server);
  Serial.print("Waiting for NTP time sync: ");
  while (time(nullptr) < 8 * 3600 * 2) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("Time synchronized");
  struct tm timeinfo;
  if (getLocalTime(&timeinfo)) {
    Serial.print("Current time: ");
    Serial.println(asctime(&timeinfo));
  } else {
    Serial.println("Failed to obtain local time");
  }
}

void connectToMQTT() {
  BearSSL::X509List serverTrustedCA(ca_cert);
  espClient.setTrustAnchors(&serverTrustedCA);
  while (!mqtt_client.connected()) {
    String client_id = "esp8266-client-" + String(WiFi.macAddress());
    Serial.printf("Connecting to MQTT Broker as %s.....\n", client_id.c_str());
    if (mqtt_client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
      Serial.println("Connected to MQTT broker");
      mqtt_client.subscribe(mqtt_topic);
      // Publish message upon successful connection
      mqtt_client.publish(topic, "Hi EMQX I'm ESP8266 ^^");
    } else {
      char err_buf[128];
      espClient.getLastSSLError(err_buf, sizeof(err_buf));
      Serial.print("Failed to connect to MQTT broker, rc=");
      Serial.println(mqtt_client.state());
      Serial.print("SSL error: ");
      Serial.println(err_buf);
      delay(5000);
    }
  }
}

void mqttCallback(char *topic, byte *payload, unsigned int length) {
  Serial.print("Message received on topic: ");
  Serial.print("[");
  Serial.print(topic);
  Serial.print("]: ");


  switch ((char)payload[0]) {
    case 'S':
      if (length == 2) {
        Speed = (payload[1] - 48);
      } else if (length == 3) {
        Speed = ((payload[2] - 48) * 10 + (payload[1] - 48));
      } else if (length == 4) {
        Speed = ((payload[3] - 48) * 100 + (payload[2] - 48) * 10 + (payload[1] - 48));
      } else if (length == 5) {
        Speed = ((payload[4] - 48) * 1000 + (payload[3] - 48) * 100 + (payload[2] - 48) * 10 + (payload[1] - 48));
      }
      ws2812fx.setSpeed(Speed);
      break;

    case 'R':
      if (length == 12) {
        colorR = ((payload[3] - 48) * 100 + (payload[2] - 48) * 10 + (payload[1] - 48));
      }
      if ((char)payload[4] == 'G') {
        colorG = ((payload[7] - 48) * 100 + (payload[6] - 48) * 10 + (payload[5] - 48));
      }
      if ((char)payload[8] == 'B') {
        colorB = ((payload[11] - 48) * 100 + (payload[10] - 48) * 10 + (payload[9] - 48));
      }

      ws2812fx.setColor(colorR, colorG, colorB);
      break;

    case 'W':
      if (length == 2) {
        colorW = (payload[1] - 48);
      } else if (length == 3) {
        colorW = ((payload[2] - 48) * 10 + (payload[1] - 48));
      } else if (length == 4) {
        colorW = ((payload[3] - 48) * 100 + (payload[2] - 48) * 10 + (payload[1] - 48));
      }
      ws2812fx.setBrightness(colorW);
      break;

    case 'M':
      if (length == 2) {
        Mode = (payload[1] - 48);
      } else if (length == 3) {
        Mode = ((payload[2] - 48) * 10 + (payload[1] - 48));
      }
      ws2812fx.setMode(Mode);
      break;

      for (int i = 0; i < length; i++) {
        Serial.print((char)payload[i]);
      }
      Serial.println();


      Serial.println(Speed);
      //      Serial.println("R:%d,G:%d,B:%d",colorR, colorG, colorB);
      Serial.println(colorW);
      Serial.println(ws2812fx.getModeName(Mode));
      Serial.println();
      Serial.println("-----------------------");
  }
}




void loop() {
  ws2812fx.service();
  if (!mqtt_client.connected()) {
    connectToMQTT();
  }
  mqtt_client.loop();
}
//72种模式
/*
#define FX_MODE_STATIC                   0
#define FX_MODE_BLINK                    1
#define FX_MODE_BREATH                   2
#define FX_MODE_COLOR_WIPE               3
#define FX_MODE_COLOR_WIPE_INV           4 
#define FX_MODE_COLOR_WIPE_REV           5
#define FX_MODE_COLOR_WIPE_REV_INV       6
#define FX_MODE_COLOR_WIPE_RANDOM        7
#define FX_MODE_RANDOM_COLOR             8
#define FX_MODE_SINGLE_DYNAMIC           9
#define FX_MODE_MULTI_DYNAMIC           10
#define FX_MODE_RAINBOW                 11
#define FX_MODE_RAINBOW_CYCLE           12
#define FX_MODE_SCAN                    13
#define FX_MODE_DUAL_SCAN               14
#define FX_MODE_FADE                    15
#define FX_MODE_THEATER_CHASE           16
#define FX_MODE_THEATER_CHASE_RAINBOW   17
#define FX_MODE_RUNNING_LIGHTS          18
#define FX_MODE_TWINKLE                 19
#define FX_MODE_TWINKLE_RANDOM          20
#define FX_MODE_TWINKLE_FADE            21
#define FX_MODE_TWINKLE_FADE_RANDOM     22
#define FX_MODE_SPARKLE                 23
#define FX_MODE_FLASH_SPARKLE           24
#define FX_MODE_HYPER_SPARKLE           25
#define FX_MODE_STROBE                  26
#define FX_MODE_STROBE_RAINBOW          27
#define FX_MODE_MULTI_STROBE            28
#define FX_MODE_BLINK_RAINBOW           29
#define FX_MODE_CHASE_WHITE             30
#define FX_MODE_CHASE_COLOR             31
#define FX_MODE_CHASE_RANDOM            32
#define FX_MODE_CHASE_RAINBOW           33
#define FX_MODE_CHASE_FLASH             34
#define FX_MODE_CHASE_FLASH_RANDOM      35
#define FX_MODE_CHASE_RAINBOW_WHITE     36
#define FX_MODE_CHASE_BLACKOUT          37
#define FX_MODE_CHASE_BLACKOUT_RAINBOW  38
#define FX_MODE_COLOR_SWEEP_RANDOM      39
#define FX_MODE_RUNNING_COLOR           40
#define FX_MODE_RUNNING_RED_BLUE        41
#define FX_MODE_RUNNING_RANDOM          42
#define FX_MODE_LARSON_SCANNER          43
#define FX_MODE_COMET                   44
#define FX_MODE_FIREWORKS               45
#define FX_MODE_FIREWORKS_RANDOM        46
#define FX_MODE_MERRY_CHRISTMAS         47
#define FX_MODE_FIRE_FLICKER            48
#define FX_MODE_FIRE_FLICKER_SOFT       49
#define FX_MODE_FIRE_FLICKER_INTENSE    50
#define FX_MODE_CIRCUS_COMBUSTUS        51
#define FX_MODE_HALLOWEEN               52
#define FX_MODE_BICOLOR_CHASE           53
#define FX_MODE_TRICOLOR_CHASE          54
#define FX_MODE_TWINKLEFOX              55
#define FX_MODE_RAIN                    56
#define FX_MODE_BLOCK_DISSOLVE          57
#define FX_MODE_ICU                     58
#define FX_MODE_DUAL_LARSON             59
#define FX_MODE_RUNNING_RANDOM2         60
#define FX_MODE_FILLER_UP               61
#define FX_MODE_RAINBOW_LARSON          62
#define FX_MODE_RAINBOW_FIREWORKS       63
#define FX_MODE_TRIFADE                 64
#define FX_MODE_VU_METER                65
#define FX_MODE_HEARTBEAT               66
#define FX_MODE_BITS                    67
#define FX_MODE_MULTI_COMET             68
#define FX_MODE_FLIPBOOK                69
#define FX_MODE_POPCORN                 70
#define FX_MODE_OSCILLATOR              71
*/